import SEO from "../components/SEO";
import { TOC, TOCList, TOCLink } from "../components/TOC";

<SEO
	title="Alert Dialog"
	description="Accessible alert dialog component for React"
/>

# Alert Dialog

<TOC>
	<TOCList>
		<TOCLink href="#alertdialog">AlertDialog</TOCLink>
		<TOCLink href="#alertdialoglabel">AlertDialogLabel</TOCLink>
		<TOCLink href="#alertdialogdescription">AlertDialogDescription</TOCLink>
		<TOCLink href="#alertdialogoverlay">AlertDialogOverlay</TOCLink>
		<TOCLink href="#alertdialogcontent">AlertDialogContent</TOCLink>
	</TOCList>
</TOC>

- Source: https://github.com/reach/reach-ui/tree/main/packages/alert-dialog
- WAI-ARIA: https://www.w3.org/TR/wai-aria-practices-1.2/#alertdialog

A modal dialog that interrupts the user's workflow to get a response, usually some sort of confirmation. This is different than a typical Dialog in that it requires some user response, like "Save", or "Cancel", etc.

Most of the time you'll use `AlertDialog`, `AlertDialogLabel`, and `AlertDialogDescription` together. If you need more control over the styling of the modal you can drop down a level and use `AlertDialogOverlay` and `AlertDialogContent` instead of `AlertDialog`.

When a Dialog opens, the _least destructive_ action should be focused so that if a user accidentally hits enter when the dialog opens no damage is done. This is accomplished with the `leastDestructiveRef` prop.

Every dialog must render an `AlertDialogLabel` so the screen reader knows what to say about the dialog. If an `AlertDialogDescription` is also rendered, the screen reader will also announce that. If you render more than these two elements and some buttons, the screen reader might not announce it so it's important to keep the content inside of `AlertDialogLabel` and `AlertDialogDescription`.

This is built on top of [Dialog](/dialog), so `AlertDialog` spreads its props and renders a `Dialog`, same for `AlertDialogOverlay` to `DialogOverlay`, and `AlertDialogContent` to `DialogContent`.

```jsx
// jsx-demo
function Example(props) {
	const [showDialog, setShowDialog] = React.useState(false);
	const cancelRef = React.useRef();
	const open = () => setShowDialog(true);
	const close = () => setShowDialog(false);

	return (
		<div>
			<button onClick={open}>Delete something</button>

			{showDialog && (
				<AlertDialog leastDestructiveRef={cancelRef}>
					<AlertDialogLabel>Please Confirm!</AlertDialogLabel>

					<AlertDialogDescription>
						Are you sure you want to delete something? This action is permanent,
						and we're totally not just flipping a field called "deleted" to
						"true" in our database, we're actually deleting something.
					</AlertDialogDescription>

					<div className="alert-buttons">
						<button onClick={close}>Yes, delete</button>{" "}
						<button ref={cancelRef} onClick={close}>
							Nevermind, don't delete.
						</button>
					</div>
				</AlertDialog>
			)}
		</div>
	);
}
```

## Installation

From the command line in your project directory, run `npm install @reach/alert-dialog` or `yarn add @reach/alert-dialog`. Then import the components that you need:

```bash
npm install @reach/alert-dialog
# or
yarn add @reach/alert-dialog
```

```js
import {
	AlertDialog,
	AlertDialogLabel,
	AlertDialogDescription,
	AlertDialogOverlay,
	AlertDialogContent,
} from "@reach/alert-dialog";
```

## Component API

### AlertDialog

High-level component to render an alert dialog.

```jsx
<AlertDialog leastDestructiveRef={someRef}>
	<AlertDialogLabel />
	<AlertDialogContent />
</AlertDialog>
```

#### AlertDialog Props

| Prop                                                      | Type   | Required |
| --------------------------------------------------------- | ------ | -------- |
| [`Dialog` props](#alertdialog-dialog-props)               |        |          |
| [`isOpen`](#alertdialog-isopen)                           | `bool` | false    |
| [`onDismiss`](#alertdialog-ondismiss)                     | `func` | false    |
| [`leastDestructiveRef`](#alertdialog-leastdestructiveref) | `func` | false    |
| [`children`](#dialog-element-props)                       | `node` | true     |

##### AlertDialog Dialog props

Any props not listed above will be spread onto the underlying `Dialog` element, which in turn is spread onto the underlying `div[data-reach-dialog-content]`.

See [documentation for `Dialog` props](/dialog#dialog-props) for more information.

```jsx
<AlertDialog style={{ color: "red" }}>
	<AlertDialogLabel>
		My text is red because the style prop got applied to the div underneath
	</AlertDialogLabel>
</AlertDialog>
```

##### AlertDialog `isOpen`

`isOpen?: boolean`

Controls whether the dialog is open or not. Defaults to `true`.

```jsx
<AlertDialog isOpen={true}>
  <AlertDialogLabel>I will be open</AlertDialogLabel>
</AlertDialog>

<AlertDialog isOpen={false}>
  <AlertDialogLabel>I will be closed</AlertDialogLabel>
</AlertDialog>
```

Note, however, that the dialog will not render to the DOM when `isOpen={false}`, but you may want to save on the number of elements created in your render function. If you'd rather not have the dialog always rendered, you can put a guard in front of it and only render when it should be open. In this case you don’t need the `isOpen` prop at all.

```jsx
{
	state.confirmDelete && (
		<AlertDialog isOpen={true}>
			<AlertDialogLabel>I will be open</AlertDialogLabel>
		</AlertDialog>
	);
}
```

You should probably do this when your dialog contains a lot of elements. It's also useful for transition animations.

##### AlertDialog `onDismiss`

`onDismiss?(event: React.MouseEvent | React.KeyboardEvent): void`

When the user clicks outside the modal or hits the escape key, this function will be called. If you want the modal to close, you’ll need to set state.

**IMPORTANT**: Ensure that `onDismiss` and the click handler of the `leastDestructiveRef` are identical!

```jsx
// jsx-demo
function Example(props) {
	const [showDialog, setShowDialog] = React.useState(false);
	const cancelRef = React.useRef();

	const open = () => setShowDialog(true);
	const destroyStuff = () => {
		console.log("Destroyed!");
		setShowDialog(false);
	};
	// make sure `close` and the `onClick` of the
	// `leastDestructiveRef` are identical, best to just
	// pass them both the same function
	const close = () => setShowDialog(false);

	return (
		<div>
			<button onClick={open}>Delete something</button>

			{showDialog && (
				<AlertDialog onDismiss={close} leastDestructiveRef={cancelRef}>
					<AlertDialogLabel>Please Confirm!</AlertDialogLabel>

					<AlertDialogDescription>
						Are you sure you want to delete something? This action is permanent,
						and we're totally not just flipping a field called "deleted" to
						"true" in our database, we're actually deleting something.
					</AlertDialogDescription>

					<div className="alert-buttons">
						<button onClick={destroyStuff}>Yes, delete</button>{" "}
						<button ref={cancelRef} onClick={close}>
							Nevermind, don't delete.
						</button>
					</div>
				</AlertDialog>
			)}
		</div>
	);
}
```

##### AlertDialog `leastDestructiveRef`

`leastDestructiveRef?: React.RefObject<HTMLElement>;`

To prevent accidental data loss, an alert dialog should focus the least destructive action button when it opens.

```jsx
// jsx-demo
function Example(props) {
	const [showDialog, setShowDialog] = React.useState(false);

	// we'll pass this ref to both AlertDialog and our button
	const cancelRef = React.useRef();

	const open = () => setShowDialog(true);
	const close = () => setShowDialog(false);

	return (
		<div>
			<button onClick={open}>Publish something</button>

			{showDialog && (
				<AlertDialog leastDestructiveRef={cancelRef}>
					<AlertDialogLabel>Please Confirm!</AlertDialogLabel>

					<AlertDialogDescription>
						Are you sure you want to publish this thing?
					</AlertDialogDescription>

					<div className="alert-buttons">
						<button onClick={this.close}>Yes, publish and keep editing</button>{" "}
						<button onClick={this.close}>Yes, publish and view</button>{" "}
						<button ref={cancelRef} onClick={close}>
							Don't publish, keep working
						</button>
					</div>
				</AlertDialog>
			)}
		</div>
	);
}
```

##### AlertDialog `children`

`children: React.ReactNode`

Accepts any renderable content but should generally be restricted to `AlertDialogLabel`, `AlertDialogDescription` and action buttons, other content might not be announced to the user by the screen reader.

```jsx
<AlertDialog>
	<AlertDialogLabel>Please Confirm!</AlertDialogLabel>

	<AlertDialogDescription>A longer message</AlertDialogDescription>

	<div>
		<button onClick={destroyStuff}>A Destructive Action</button>{" "}
		<button ref={leastDestructiveRef}>Least Destructive Action</button>
	</div>
</AlertDialog>
```

### AlertDialogLabel

The first thing ready by screen readers when the dialog opens, usually the title of the dialog like "Warning!" or "Please confirm!".

This is required. The `AlertDialog` will throw an error if no label is rendered.

#### AlertDialogLabel CSS Selectors

Please see the [styling guide](/styling).

Use the following CSS to target the label:

```css
[data-reach-alert-dialog-label] {
}
```

#### AlertDialogLabel Props

| Prop                                       |
| ------------------------------------------ |
| [`div` props](#alertdialoglabel-div-props) |

##### AlertDialogLabel `div` props

All props are spread to an underlying `div` element.

```jsx
<AlertDialogLabel className="alert-label" />
```

### AlertDialogDescription

Additional content read by screen readers, usually a longer description about what you need from the user like "This action is permanent, are you sure?" etc.

#### AlertDialogDescription CSS Selectors

Please see the [styling guide](/styling).

Use the following CSS to target the description:

```css
[data-reach-alert-dialog-description] {
}
```

#### AlertDialogDescription Props

| Prop                                             |
| ------------------------------------------------ |
| [`div` props](#alertdialogdescription-div-props) |

##### AlertDialogDescription `div` props

All props are spread to an underlying `div` element.

```jsx
<AlertDialogDescription className="alert-description" />
```

### AlertDialogOverlay

Low-level component if you need more control over the styles or rendering of the dialog overlay. In the following example we use the AlertDialogOverlay and AlertDialogContent to have more control over the styles.

Note: You must render an `AlertDialogContent` inside.

```jsx
// jsx-demo
function Example(props) {
	const [showDialog, setShowDialog] = React.useState(false);

	// we'll pass this ref to both AlertDialog and our button
	const cancelRef = React.useRef();

	const open = () => setShowDialog(true);
	const close = () => setShowDialog(false);

	return (
		<div>
			<button onClick={open}>Delete something</button>

			{showDialog && (
				<AlertDialogOverlay
					style={{ background: "hsla(0, 50%, 50%, 0.85)" }}
					leastDestructiveRef={cancelRef}
				>
					<AlertDialogContent style={{ background: "#f0f0f0" }}>
						<AlertDialogLabel>Please Confirm!</AlertDialogLabel>

						<AlertDialogDescription>
							Are you sure you want delete stuff, it will be permanent.
						</AlertDialogDescription>

						<div className="alert-buttons">
							<button onClick={close}>Yes, delete</button>{" "}
							<button ref={cancelRef} onClick={close}>
								Nevermind
							</button>
						</div>
					</AlertDialogContent>
				</AlertDialogOverlay>
			)}
		</div>
	);
}
```

#### AlertDialogOverlay CSS Selectors

Please see the [styling guide](/styling).

Use the following CSS to target the overlay:

```css
[data-reach-alert-dialog-overlay] {
}
```

#### AlertDialogOverlay Props

| Prop                                                             | Type   | Required |
| ---------------------------------------------------------------- | ------ | -------- |
| [`DialogOverlay` props](#alertdialogoverlay-dialogoverlay-props) |        |          |
| [`isOpen`](#alertdialogoverlay-isopen)                           | `bool` | false    |
| [`onDismiss`](#alertdialogoverlay-ondismiss)                     | `func` | false    |
| [`leastDestructiveRef`](#alertdialogoverlay-leastdestructiveref) | `ref`  | false    |
| [`children`](#alertdialogoverlay-children)                       | `node` | true     |

##### AlertDialogOverlay `DialogOverlay` props

Any props not listed above will be spread onto the underlying `DialogOverlay`, and in turn spread onto the underlying `div` element.

See [documentation for `DialogOverlay` props](/dialog#dialogoverlay-props) for more information.

```jsx
<AlertDialogOverlay className="light-modal" />
```

##### AlertDialogOverlay `isOpen`

`isOpen?: boolean`

Same as [`AlertDialog` `isOpen`](#alertdialog-isopen). Defaults to `true`.

##### AlertDialogOverlay `onDismiss`

`onDismiss?(event: React.MouseEvent | React.KeyboardEvent): void`

Same as [`AlertDialog` `onDismiss`](#alertdialog-ondismiss)

##### AlertDialogOverlay `leastDestructiveRef`

`leastDestructiveRef?: React.RefObject<HTMLElement>`

Same as [`AlertDialog` `leastDestructiveRef`](#alertdialog-leastdestructiveref)

##### AlertDialogOverlay `children`

`children: React.ReactNode`

Should be an `AlertDialogContent`.

```jsx
<AlertDialogOverlay>
	<AlertDialogContent />
</AlertDialogOverlay>
```

### AlertDialogContent

Low-level component if you need more control over the styles or rendering of the dialog content.

Note: Must be a child of `AlertDialogOverlay`.

Note: You only need to use this when you are also styling `AlertDialogOverlay`, otherwise you can use the high-level `AlertDialog` component and pass the props to it.

```jsx
<AlertDialogOverlay style={someSpecificStyles}>
	<AlertDialogContent className={orAClassName} />
</AlertDialogOverlay>
```

#### AlertDialogContent CSS Selectors

Please see the [styling guide](/styling).

Use the following CSS to target the content:

```css
[data-reach-alert-dialog-content] {
}
```

#### AlertDialogContent Props

| Prop                                                             | Type   | Required |
| ---------------------------------------------------------------- | ------ | -------- |
| [`DialogContent` props](#alertdialogcontent-dialogcontent-props) |        |          |
| [`children`](#alertdialogcontent-element-props)                  | `node` | true     |

##### AlertDialogContent `DialogContent` props

Any props not listed above will be spread onto the underlying `DialogContent` element, and then again onto the underlying `div`.

See [documentation for `DialogContent` props](/dialog#dialogcontent-props) for more information.

```jsx
<AlertDialogContent className="nice-border" />
```

##### AlertDialogContent `children`

`children: React.ReactNode`

Same as [`AlertDialog` `children`](#alertdialog-children)
